package rs;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import org.jsoup.nodes.Document;
import org.nutz.json.Json;
import org.nutz.lang.Files;

import rs.util.FolderListener;
import rs.util.FolderMonitor;
import rs.util.Log;
import rs.util.StringUtil;
import rs.util.TimeUtil;

public class ProjectManager {
	/*
	改动:
		去掉JobManager,
		Boss只管理ProjectManager,
		ProjectManager初始化时标识所有的job类型,
		ProjectManager负责解析project描述,
		并抓取生成JobDesc列表,
		按照定时策略将JobDesc交由JobProcessor完成.
	
	ProjectManager 职责:
	监视jobs文件夹,记录job类型.
	监视projects文件,
	*/
	//存储jobDesc
	public static HashMap<String, JobDesc> JOB_TYPES = new HashMap<String, JobDesc>();
	//存储projectDesc
	public static HashMap<String, ProjectDesc> PROJECT_TYPES = new HashMap<String, ProjectDesc>();
	// task缓存,标识已经添加的任务.
	public static HashMap<String, Object> TASKS_ADDED = new HashMap<String, Object>();
	// 标识task已创建的占位符对象
	private static final Object BLANK_OBJECT = new Object();
	
	
	public void work(){
		JobManager jobManager = new JobManager();
		jobManager.work();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		FolderMonitor monitor = new FolderMonitor(Conf.PROJECT_DESCRIPTION_DIR,
				Conf.PROJECT_CHECKING_PERIOD_IN_SECOND, new FolderListener() {
					
					// we care.
					public void onFileModified(String absolutePath) {
						//XXX 更新工单描述?
						//TODO 完成更新工单逻辑
					}
					
					public void onFileCreated(String absolutePath) {
						
						onNewProjectDesc(absolutePath);
					}
					@Override
					public void afterFirstScan() {
						listenTasks();
					}
				}, true);
		new Thread(monitor).start();
		
	}
	
	protected void listenTasks() {
		FolderMonitor monitor = new FolderMonitor(Conf.TASK_DIR,
				Conf.TASK_CHECKING_PERIOD_IN_SECOND, new FolderListener() {
					
					// we care.
					public void onFileModified(String absolutePath) {
						onNewTask(absolutePath);
					}
					
					public void onFileCreated(String absolutePath) {
						
						onNewTask(absolutePath);
					}
					@Override
					public void afterFirstScan() {
						//addTasks();
					}
				}, true);
		new Thread(monitor).start();
	}

	@SuppressWarnings("unchecked")
	protected void onNewTask(String absolutePath) {
		String taskJson = Files.read(absolutePath);
		List<TreeMap> tasks = (LinkedList<TreeMap>)Json.fromJson(taskJson);
		if(tasks == null){
			return;
		}
		for(TreeMap treeMap: tasks){
			Task task = Json.fromJson(Task.class, Json.toJson(treeMap));
			if(null == TASKS_ADDED.get(task.url)){
				TASKS_ADDED.put(task.url, BLANK_OBJECT);
				addTask(task);
			}
		}
	}

	private void onNewProjectDesc(String absolutePath){
		String projectJson = Files.read(absolutePath);
		addAProjectDesc(projectJson);
		
	}

	/**
	 * 添加一个project描述,并立即执行
	 * @param projectJson project描述
	 */
	public void addAProjectDesc(String projectJson) {
		ProjectDesc projectDesc = Json.fromJson(ProjectDesc.class, projectJson);
		addAProjectDesc(projectDesc);
	}
	
	/**
	 * 添加一个project描述,并立即执行
	 * @param projectDesc project描述
	 */
	public void addAProjectDesc(ProjectDesc projectDesc) {
		if(projectDesc == null ){
			return;
		}
		PROJECT_TYPES.put(projectDesc.id, projectDesc);
		//runTask(projectDesc);
	}
	
	public void addTask(Task task){
		String jobId = task.id;
		String[] urls = new String[]{task.url};
		if("project".equalsIgnoreCase(task.type)){
			ProjectDesc projectDesc = PROJECT_TYPES.get(task.id);
			if(projectDesc == null){
				Log.error("ERROR: NO PROJECT WITH ID: " + task.id);
				return;
			}
			projectDesc = projectDesc.clone();
			projectDesc.url = task.url;
			
			Document doc;
			try {
				doc = new Crawler().work(projectDesc.url);
			} catch (MalformedURLException e) {
				e.printStackTrace();
				return;
			} catch (IOException e) {
				e.printStackTrace();
				return;
			}
			Map<String, String> rules = new HashMap<String, String>();
			String key = "jobUrls";
			rules.put(key, projectDesc.jobUrls);
			Map<String, Object> result = new HashMap<String, Object>();
			new Extractor().work(doc, rules, result);
			urls = (String[])result.get(key);
			jobId = projectDesc.jobId;
		}
		JobDesc jobDesc = JOB_TYPES.get(jobId);
		if(jobDesc == null){
			Log.error("ERROR: NO JOB WITH ID: " + jobId);
			return;
		}
		jobDesc = jobDesc.clone();
		if(StringUtil.notEmpty(task.tag)){
			jobDesc.tag = task.tag;
		}
		for(String url : urls){
			JobDesc aJob = jobDesc.clone();
			aJob.url = url;
			//如果有fixer,则fix之.
			aJob = JobDescFixer.fix(aJob);
			
			JobProcessor jobProcessor = new JobProcessor(aJob);
			long delay = Timer.delayOf(url);
			JobManager.JOB_CENTER.scheduleAtFixedRate(jobProcessor, delay, TimeUtil.PERIOD_DAY, TimeUnit.MILLISECONDS);
		}
	}
	
}
